// -*- coding: utf-8 -*-

#include <iostream>
#include <string>

#include "elisa/elisa.h"

#include "Modeler.h"

using namespace std;
using namespace elisa;

class Falling2 : public Modeler
{
private:
	static const VNInterval G, K, E;

	ContVar p1;
	ContVar p2;
	ContVar p3;
	ContVar p4;
	ContVar p5;
	ContVar p6;
	ContVar p7;
	ContVar p8;
	ContVar p9;
	ContVar p10;
	ContVar p11;
	ContVar p12;
	ContVar p13;
	ContVar p14;
	ContVar p15;
	ContVar p16;

	static Interval Time;
	static VNInterval P;

public:
	Falling2()
		: Modeler(Time),
		  p1(P, "p1"),
		  p2(P, "p2"),
		  p3(P, "p3"),
		  p4(P, "p4"),
		  p5(P, "p5"),
		  p6(P, "p6"),
		  p7(P, "p7"),
		  p8(P, "p8"),
		  p9(P, "p9"),
		  p10(P, "p10"),
		  p11(P, "p11"),
		  p12(P, "p12"),
		  p13(P, "p13"),
		  p14(P, "p14"),
		  p15(P, "p15"),
		  p16(P, "p16")
	{
		double p;
		if (p != 0.0)
			elisa::RealVar::SetPrecision(p);
		else
			elisa::RealVar::SetPrecision(1.0e-1);
		// FIXME
		elisa::RealVar::SetPrecision(1.0e-1);

		p = 1.0e-2;
		//p = 1.0e-11;
		t.setPrecision(std::max<double>(p, Time.width()*10));

		elisa::RealVar::SetPrecision(std::max<double>(p, Time.width()*10));

		t.setDomain(new Interval(Time.inf(), 1.0e4));

		addVar(p1);
		addVar(p2);
		addVar(p3);
		addVar(p4);
		addVar(p5);
		addVar(p6);
		addVar(p7);
		addVar(p8);
		addVar(p9);
		addVar(p10);
		addVar(p11);
		addVar(p12);
		addVar(p13);
		addVar(p14);
		addVar(p15);
		addVar(p16);
	}

	// 連続制約の定義
	template<typename T>
	static void flow(int n, T *dv, const T *v, T t, void *param)
	{
		dv[0] = -G + K*sqr(v[1]);
		dv[1] = -G + K*sqr(v[2]);
		dv[2] = -G + K*sqr(v[3]);
		dv[3] = -G + K*sqr(v[4]);
		dv[4] = -G + K*sqr(v[5]);
		dv[5] = -G + K*sqr(v[6]);
		dv[6] = -G + K*sqr(v[7]);
		dv[7] = -G + K*sqr(v[8]);
		dv[8] = -G + K*sqr(v[9]);
		dv[9] = -G + K*sqr(v[10]);
		dv[10] = -G + K*sqr(v[11]);
		dv[11] = -G + K*sqr(v[12]);
		dv[12] = -G + K*sqr(v[13]);
		dv[13] = -G + K*sqr(v[14]);
		dv[14] = -G + K*sqr(v[15]);
		dv[15] = -G + K*sqr(v[15]);
	}

	// ガード制約の定義
	template<typename T> 
	static T guard(const std::vector<T>& v, const T& t)
	{
		return v[0];
	}

	bool reset(bool first)
	{
		//return true;
		return first ? true : false;
	}
	
	void print(std::ostream& out) const
	{
		out << '\t' << t.getName() << " = " << t.domain() << endl;
		out << '\t' << "p" << " = " << p1.domain() << endl;
	}
};

MODEL(Falling2)


const VNInterval Falling2::G(VNInterval(98)/10);
const VNInterval Falling2::K(VNInterval(1)/1000);
const VNInterval Falling2::E(0.7);

Interval Falling2::Time(Interval::Zero);
VNInterval Falling2::P(10.0);
